Completed
Push — master ( 45d7a1...2503bc )
by Sander
11s
created

angular.service(ꞌCredentialServiceꞌ)   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 160

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
c 1
b 0
f 0
nc 1
nop 3
dl 0
loc 160
rs 8.2857

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
/**
2
 * Nextcloud - passman
3
 *
4
 * @copyright Copyright (c) 2016, Sander Brand ([email protected])
5
 * @copyright Copyright (c) 2016, Marcos Zuriaga Miguel ([email protected])
6
 * @license GNU AGPL version 3 or any later version
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License as
10
 * published by the Free Software Foundation, either version 3 of the
11
 * License, or (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU Affero General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Affero General Public License
19
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
 *
21
 */
22
23
(function () {
24
	'use strict';
25
	/**
26
	 * @ngdoc service
27
	 * @name passmanApp.CredentialService
28
	 * @description
29
	 * # CredentialService
30
	 * Service in the passmanApp.
31
	 */
32
	angular.module('passmanApp')
33
		.service('CredentialService', ['$http', 'EncryptService', 'VaultService', 'FileService', function ($http, EncryptService, VaultService, FileService) {
34
			var credential = {
35
				'credential_id': null,
36
				'guid': null,
37
				'vault_id': null,
38
				'label': null,
39
				'description': null,
40
				'created': null,
41
				'changed': null,
42
				'tags': [],
43
				'email': null,
44
				'username': null,
45
				'password': null,
46
				'url': null,
47
				'favicon': null,
48
				'renew_interval': null,
49
				'expire_time': 0,
50
				'delete_time': 0,
51
				'files': [],
52
				'custom_fields': [],
53
				'otp': {},
54
				'hidden': false
55
			};
56
			var _encryptedFields = ['description', 'username', 'password', 'files', 'custom_fields', 'otp', 'email', 'tags', 'url'];
57
58
59
			return {
60
				newCredential: function () {
61
					return angular.copy(credential);
62
				},
63
				createCredential: function (credential) {
64
					var _credential = angular.copy(credential);
65
					for (var i = 0; i < _encryptedFields.length; i++) {
66
						var field = _encryptedFields[i];
67
						var fieldValue = angular.copy(credential[field]);
68
						_credential[field] = EncryptService.encryptString(JSON.stringify(fieldValue));
69
					}
70
71
					_credential.expire_time = new Date(angular.copy(credential.expire_time)).getTime() / 1000;
72
73
					var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials');
74
					return $http.post(queryUrl, _credential).then(function (response) {
75
						if (response.data) {
76
							return response.data;
77
						} else {
78
							return response;
79
						}
80
					});
81
				},
82
				getEncryptedFields: function () {
83
					return _encryptedFields;
84
				},
85
				updateCredential: function (credential, skipEncyption) {
86
					var _credential = angular.copy(credential);
87
					if (!skipEncyption) {
88
						for (var i = 0; i < _encryptedFields.length; i++) {
89
							var field = _encryptedFields[i];
90
							var fieldValue = angular.copy(credential[field]);
91
							_credential[field] = EncryptService.encryptString(JSON.stringify(fieldValue));
92
						}
93
					}
94
					_credential.expire_time = new Date(angular.copy(credential.expire_time)).getTime() / 1000;
95
96
					var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials/' + credential.guid);
97
					return $http.patch(queryUrl, _credential).then(function (response) {
98
						if (response.data) {
99
							return response.data;
100
						} else {
101
							return response;
102
						}
103
					});
104
				},
105
				getCredential: function (guid) {
106
					var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials/' + guid);
107
					return $http.get(queryUrl).then(function (response) {
108
						if (response.data) {
109
							return response.data;
110
						} else {
111
							return response;
112
						}
113
					});
114
				},
115
				destroyCredential: function (guid) {
116
					var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials/' + guid);
117
					return $http.delete(queryUrl).then(function (response) {
118
						if (response.data) {
119
							return response.data;
120
						} else {
121
							return response;
122
						}
123
					});
124
				},
125
				encryptCredential: function (credential, key) {
126
					for (var i = 0; i < _encryptedFields.length; i++) {
127
						var field = _encryptedFields[i];
128
						var fieldValue = angular.copy(credential[field]);
129
						credential[field] = EncryptService.encryptString(JSON.stringify(fieldValue), key);
130
					}
131
					return credential;
132
				},
133
				decryptCredential: function (credential, key) {
134
					for (var i = 0; i < _encryptedFields.length; i++) {
135
						var field = _encryptedFields[i];
136
						var fieldValue = angular.copy(credential[field]);
137
						var field_decrypted_value;
138
						try {
139
							field_decrypted_value = EncryptService.decryptString(fieldValue, key);
140
						} catch (e) {
141
							throw e;
142
						}
143
						try {
144
							credential[field] = JSON.parse(field_decrypted_value);
145
						} catch (e) {
146
							console.warn('Field' + field + ' in ' + credential.label + ' could not be parsed! Value:' + fieldValue);
147
148
						}
149
150
					}
151
					return credential;
152
				},
153
				getRevisions: function (guid) {
154
					var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials/' + guid + '/revision');
155
					return $http.get(queryUrl).then(function (response) {
156
						if (response.data) {
157
							return response.data;
158
						} else {
159
							return response;
160
						}
161
					});
162
				},
163
				updateRevision: function (revision) {
164
					var _revision = angular.copy(revision);
165
					_revision.credential_data = window.btoa(JSON.stringify(_revision.credential_data));
166
					var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials/' + revision.credential_data.guid + '/revision/' + revision.revision_id);
167
					return $http.patch(queryUrl, _revision).then(function (response) {
168
						if (response.data) {
169
							return response.data;
170
						} else {
171
							return response;
172
						}
173
					});
174
				},
175
				deleteRevision: function (credential_guid, revision_id) {
176
					var queryUrl = OC.generateUrl('apps/passman/api/v2/credentials/' + credential_guid + '/revision/' + revision_id);
177
					return $http.delete(queryUrl).then(function (response) {
178
						if (response.data) {
179
							return response.data;
180
						} else {
181
							return response;
182
						}
183
					});
184
				},
185
				reencryptCredential: function (credential_guid, old_password, new_password) {
186
187
					var service = this;
188
189
					var progress_datatype = function (current, total, process) {
190
						this.process = process;
191
						this.current = current;
192
						this.total = total;
193
						this.calculated = current / total * 100;
194
					};
195
196
					var promise_credential_update = function () {
197
						service.getCredential(credential_guid).then((function (credential) {
198
							this.parent.plain_credential = service.decryptCredential(credential, this.parent.old_password);
199
							var tmp = angular.copy(this.parent.plain_credential);
200
201
							//@FIXME Your shared credentials are not updated properly
202
							if (tmp.hasOwnProperty('shared_key') && tmp.shared_key !== null) {
203
								var shared_key = EncryptService.decryptString(angular.copy(tmp.shared_key)).trim();
204
								tmp.shared_key = EncryptService.encryptString(angular.copy(shared_key), this.parent.new_password);
205
								tmp.set_share_key = true;
206
								tmp.skip_revision = true;
207
								this.parent.new_password = shared_key;
208
							}
209
210
							this.parent.new_credential_cryptogram = service.encryptCredential(tmp, this.parent.new_password);
211
							this.call_progress(new progress_datatype(1, 2, 'credential'));
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like progress_datatype should be capitalized.
Loading history...
212
213
							// Save data
214
							this.parent.new_credential_cryptogram.skip_revision = true;
215
							service.updateCredential(this.parent.new_credential_cryptogram, true).then((function () {
216
								this.call_progress(new progress_datatype(2, 2, 'credential'));
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like progress_datatype should be capitalized.
Loading history...
217
								this.call_then({
218
									plain_text: this.parent.plain_credential,
219
									cryptogram: this.parent.new_credential_cryptogram
220
								});
221
							}).bind(this));
222
						}).bind(this));
223
					};
224
225
					var promise_files_update = function () {
226
						// Add the double of the files so we take encryption phase and upload to the server into the math
227
						this.total = this.parent.plain_credential.files.length * 2;	 // Binded on credential finish upload
228
						this.current = 0;
229
230
						for (var i = 0; i < this.parent.plain_credential.files.length; i++) {
231
							var _file = this.parent.plain_credential.files[i];
232
							/* jshint ignore:start */
233
							FileService.getFile(_file).then((function (fileData) {
234
								//Decrypt with old key
235
								fileData.filename = EncryptService.decryptString(fileData.filename, this.parent.old_password);
236
								fileData.file_data = EncryptService.decryptString(fileData.file_data, this.parent.old_password);
237
238
								this.current++;
239
240
								this.call_progress(new progress_datatype(this.current, this.total, 'files'));
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like progress_datatype should be capitalized.
Loading history...
241
242
								FileService.updateFile(fileData, this.parent.new_password).then((function () {
243
									this.current++;
244
									this.call_progress(new progress_datatype(this.current, this.total, 'files'));
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like progress_datatype should be capitalized.
Loading history...
245
									if (this.current === this.total) {
246
										this.call_then('All files has been updated');
247
									}
248
								}).bind(this));
249
							}).bind(this));
250
							/* jshint ignore:end */
251
						}
252
						if (this.parent.plain_credential.files.length === 0) {
253
							this.call_progress(new progress_datatype(0, 0, 'files'));
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like progress_datatype should be capitalized.
Loading history...
254
							this.call_then("No files to update");
255
						}
256
					};
257
258
					var promise_revisions_update = function () {
259
						service.getRevisions(this.parent.plain_credential.guid).then((function (revisions) {
260
							// Double, so we include the actual upload of the data back to the server
261
							this.total = revisions.length * 2;
262
							this.upload = 0;
263
							this.current = 0;
264
							this.revisions = revisions;
265
266
							var revision_workload = function () {
267
								if (this.revisions.length === 0) {
268
									this.call_progress(new progress_datatype(0, 0, 'revisions'));
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like progress_datatype should be capitalized.
Loading history...
269
									this.call_then("No history to update");
270
									return;
271
								}
272
								var _revision = revisions[this.current];
273
								//Decrypt!
274
								_revision.credential_data = service.decryptCredential(_revision.credential_data, this.parent.old_password);
275
								_revision.credential_data = service.encryptCredential(_revision.credential_data, this.parent.new_password);
276
								this.current++;
277
278
								this.call_progress(new progress_datatype(this.current + this.upload, this.total, 'revisions'));
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like progress_datatype should be capitalized.
Loading history...
279
280
								service.updateRevision(_revision).then((function () {
281
									this.upload++;
282
									this.call_progress(new progress_datatype(this.upload + this.current, this.total, 'revisions'));
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like progress_datatype should be capitalized.
Loading history...
283
									if (this.current + this.upload === this.total) {
284
										this.call_then("History updated");
285
									}
286
								}).bind(this));
287
288
								if (this.current !== (this.total / 2)) {
289
									setTimeout(revision_workload.bind(this), 1);
290
								}
291
							};
292
							setTimeout(revision_workload.bind(this), 1);
293
						}).bind(this));
294
					};
295
296
					var promise_workload = function () {
297
						this.old_password = angular.copy(old_password);
298
						this.new_password = angular.copy(new_password);
299
						this.promises = 0;
300
301
						var master_promise = this;
302
303
						var password_data = function () {
304
							this.old_password = master_promise.old_password;
305
							this.new_password = master_promise.new_password;
306
							this.plain_credential = master_promise.plain_credential;
307
						};
308
						this.credential_data = {};
309
						/** global: C_Promise */
310
						(new C_Promise(promise_credential_update, new password_data())).progress(function (data) {
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like password_data should be capitalized.
Loading history...
311
							master_promise.call_progress(data);
312
						}).then(function (data) {
313
							console.warn("End credential update");
314
							master_promise.plain_credential = data.plain_text;
315
							master_promise.promises++;
316
317
							master_promise.credential_data = data;
318
							/** global: C_Promise */
319
							(new C_Promise(promise_files_update, new password_data())).progress(function (data) {
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like password_data should be capitalized.
Loading history...
320
								master_promise.call_progress(data);
321
							}).then(function () {
322
								console.warn("End files update");
323
								master_promise.promises--;
324
								if (master_promise.promises === 0) {
325
									master_promise.call_then(master_promise.credential_data);
326
								}
327
							});
328
329
							master_promise.promises++;
330
							/** global: C_Promise */
331
							(new C_Promise(promise_revisions_update, new password_data())).progress(function (data) {
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like password_data should be capitalized.
Loading history...
332
								master_promise.call_progress(data);
333
							}).then(function () {
334
								console.warn("End revisions update");
335
								master_promise.promises--;
336
								if (master_promise.promises === 0) {
337
									master_promise.call_then(master_promise.credential_data);
338
								}
339
							});
340
						});
341
					};
342
					/** global: C_Promise */
343
					return new C_Promise(promise_workload);
344
				}
345
			};
346
		}]);
347
}());